﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace XKControlLib.DesignControl
{
    public class Designer : DesignerBase
    {
        private const int GridSize = 6;
        private Point MouseDownPoint = new Point();
        private Control withEventsField_Parent;
        private bool bChangeSize;
        private bool bMoveLocation;

        private Control Parent
        {
            get { return withEventsField_Parent; }
            set
            {
                if (withEventsField_Parent != null)
                {
                    withEventsField_Parent.ControlAdded -= _ParentObject_ControlAdded;
                    withEventsField_Parent.ControlRemoved -= _ParentObject_ControlRemoved;
                    withEventsField_Parent.MouseDown -= _ParentObject_MouseDown;
                    withEventsField_Parent.MouseMove -= _ParentObject_MouseMove;
                    withEventsField_Parent.MouseUp -= _ParentObject_MouseUp;
                }
                withEventsField_Parent = value;
                if (withEventsField_Parent != null)
                {
                    withEventsField_Parent.ControlAdded += _ParentObject_ControlAdded;
                    withEventsField_Parent.ControlRemoved += _ParentObject_ControlRemoved;
                    withEventsField_Parent.MouseDown += _ParentObject_MouseDown;
                    withEventsField_Parent.MouseMove += _ParentObject_MouseMove;
                    withEventsField_Parent.MouseUp += _ParentObject_MouseUp;
                }
            }
        }

        private void _ParentObject_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int x = Convert.ToInt32((MouseDownPoint.X < e.X ? MouseDownPoint.X : e.X));
                int y = Convert.ToInt32((MouseDownPoint.Y < e.Y ? MouseDownPoint.Y : e.Y));
                int Width = Math.Abs(MouseDownPoint.X - e.X);
                int Height = Math.Abs(MouseDownPoint.Y - e.Y);
                Rectangle rect = new Rectangle(x, y, Width, Height);
                this._SelectedObjects = this.getControls_byRectangle(this.ParentObject, rect);
                if (this.SelectedObjects.ExistItem())
                {
                    this.SelectedObject = this.SelectedObjects[0];
                }
                else
                {
                    this.SelectedObject = null;
                }
                this.ParentObject.Refresh();
                this.SignChooseControls();
            }
        }

        private ConCollection getControls_byRectangle(Control parentObject, Rectangle rect)
        {
            ConCollection cons = new ConCollection();
            foreach (Control con in Parent.Controls)
            {
                if (isChoosed(con, rect) == true & con.Visible)
                {
                    cons.Add(con);
                }
            }
            return cons;
        }

        private bool isChoosed(Control con, Rectangle rect)
        {
            Rectangle rect2 = new Rectangle(con.Left, con.Top, con.Width, con.Height);
            if (isChoosed(rect, rect2))
            {
                return true;
            }
            if (isChoosed(rect2, rect))
            {
                return true;
            }
            return false;
        }

        private bool isChoosed(Rectangle rect1, Rectangle rect2)
        {
            Point P1 = new Point(rect1.X, rect1.Y);
            Point P2 = new Point(rect1.X + rect1.Width, rect1.Y);
            Point P3 = new Point(rect1.X, rect1.Y + rect1.Height);
            Point P4 = new Point(rect1.X + rect1.Width, rect1.Y + rect1.Height);
            if (isChoosed(P1, rect2))
            {
                return true;
            }
            if (isChoosed(P2, rect2))
            {
                return true;
            }
            if (isChoosed(P3, rect2))
            {
                return true;
            }
            if (isChoosed(P4, rect2))
            {
                return true;
            }
            return false;
        }

        private bool isChoosed(Point P, Rectangle rect)
        {
            if (P.X > rect.X & P.X < rect.X + rect.Width & P.Y > rect.Y & P.Y < rect.Y + rect.Height)
            {
                return true;
            }
            return false;
        }

        private void _ParentObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Graphics g = this.ParentObject.CreateGraphics();
                g.Clear(this.ParentObject.BackColor);
                int x = Convert.ToInt32((MouseDownPoint.X < e.X ? MouseDownPoint.X : e.X));
                int y = Convert.ToInt32((MouseDownPoint.Y < e.Y ? MouseDownPoint.Y : e.Y));
                int Width = Math.Abs(MouseDownPoint.X - e.X);
                int Height = Math.Abs(MouseDownPoint.Y - e.Y);
                Rectangle rect = new Rectangle(x, y, Width, Height);
                Pen pen = new Pen(Color.Black, 1);
                pen.DashStyle = DashStyle.Custom;
                pen.DashPattern = new float[] {
                        1,
                        1
                    };
                g.DrawRectangle(pen, rect);
            }
        }

        private void _ParentObject_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                MouseDownPoint.X = e.X;
                MouseDownPoint.Y = e.Y;
            }
        }

        private void _ParentObject_ControlRemoved(object sender, ControlEventArgs e)
        {
            RemoveHandle(e.Control);
        }

        private void _ParentObject_ControlAdded(object sender, ControlEventArgs e)
        {
            RemoveHandle(e.Control);
            AddHandle(e.Control);
        }

        public override void SignChooseControls()
        {
            foreach (Control con in this.ParentObject.Controls)
            {
                con.Refresh();
            }
            foreach (Control con in this.SelectedObjects)
            {
                DrawControl(con);
            }
        }

        private void DrawControl(Control con)
        {
            if (con == SelectedObject)
            {
                DrawControl(con, true);
            }
            else
            {
                DrawControl(con, false);
            }
        }

        private void DrawControl(Control item, bool v)
        {
            Point[] ps = new Point[8];
            ps[0] = new Point(0, 0);
            ps[1] = new Point((item.Width - GridSize) / 2, 0);
            ps[2] = new Point(item.Width - GridSize, 0);
            ps[3] = new Point(0, (item.Height - GridSize) / 2);
            ps[4] = new Point(item.Width - GridSize, (item.Height - GridSize) / 2);
            ps[5] = new Point(0, item.Height - GridSize);
            ps[6] = new Point((item.Width - GridSize) / 2, item.Height - GridSize);
            ps[7] = new Point(item.Width - GridSize, item.Height - GridSize);
            DrawControl(item, ps, v);
        }

        private void DrawControl(Control item, Point[] ps, bool v)
        {
            item.Refresh();
            Graphics draw = item.CreateGraphics();
            foreach (var p in ps)
            {
                if (v)
                {
                    draw.FillRectangle(Brushes.Blue, p.X, p.Y, GridSize - 1, GridSize - 1);
                }
                else
                {
                    draw.DrawRectangle(Pens.Blue, p.X, p.Y, GridSize - 1, GridSize - 1);
                }
            }
            var pen = new Pen(Brushes.Blue, 1);
            pen.DashStyle = DashStyle.Custom;
            pen.DashPattern = new float[] { 1, 1 };
            var rect = new Rectangle(0, 0, item.Width - 1, item.Height - 1);
            draw.DrawRectangle(pen, rect);
        }

        public override Control ParentObject
        {
            get => _ParentObject;
            set
            {
                if (_ParentObject != null)
                {
                    foreach (Control con in _ParentObject.Controls)
                    {
                        RemoveHandle(con);
                    }
                }
                _ParentObject = value;
                Parent = value;
                if (_ParentObject != null)
                {
                    foreach (Control con in _ParentObject.Controls)
                    {
                        AddHandle(con);
                    }
                }
            }
        }

        private void AddHandle(Control con)
        {
            con.MouseMove += this.con_MouseMove;
            con.MouseLeave += this.con_MouseLeave;
            con.MouseDown += this.con_MouseDown;
            con.MouseUp += this.con_MouseUp;
        }

        private void RemoveHandle(Control con)
        {
            con.MouseMove -= this.con_MouseMove;
            con.MouseLeave -= this.con_MouseLeave;
            con.MouseDown -= this.con_MouseDown;
            con.MouseUp -= this.con_MouseUp;
        }

        private void con_MouseUp(object sender, MouseEventArgs e)
        {
            bChangeSize = false;
            bMoveLocation = false;
        }

        private void con_MouseLeave(object sender, EventArgs e)
        {
            Control con = (Control)sender;
            con.Cursor = Cursors.Default;
        }

        private void con_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                Control con = (Control)sender;
                if (this.SelectedObjects.Contains((Control)sender))
                {
                    this.SelectedObject = (Control)sender;
                }
                else
                {
                    if ((Control.ModifierKeys & Keys.Control) == Keys.Control && (Control.ModifierKeys & Keys.Shift) == Keys.Shift)
                    {
                        this.SelectedObjects.Clear();
                    }
                    this.SelectedObjects.Add((Control)sender);
                    this.SelectedObject = (Control)sender;
                }
                if (e.X > con.Width - Designer.GridSize)
                {
                    bChangeSize = true;
                }
                else if (e.Y > con.Height - Designer.GridSize)
                {
                    bChangeSize = true;
                }
                else
                {
                    bMoveLocation = true;
                }

                MouseDownPoint.X = e.X;
                MouseDownPoint.Y = e.Y;
                this.SignChooseControls();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void con_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                Control con = (Control)sender;
                if (this.SelectedObjects.Contains(con) == false)
                {
                    return;
                }
                if (bChangeSize == true)
                {
                    int OffsetWidth = e.X - con.Width;
                    int OffsetHeight = e.Y - con.Height;
                    if (con.Cursor == Cursors.SizeWE)
                    {
                        this.OffsetWidth(OffsetWidth);
                    }
                    else if (con.Cursor == Cursors.SizeNS)
                    {
                        this.OffsetHeight(OffsetHeight);
                    }
                    this.SignChooseControls();
                }
                else if (bMoveLocation == true & (con.Cursor == Cursors.Default | con.Cursor == Cursors.SizeAll))
                {
                    int OffsetLeft = e.X - MouseDownPoint.X;
                    int OffsetTop = e.Y - MouseDownPoint.Y;
                    this.OffsetLeft(OffsetLeft);
                    this.OffsetTop(OffsetTop);
                    this.SignChooseControls();
                }
                else
                {
                    if (e.X > con.Width - Designer.GridSize)
                    {
                        con.Cursor = Cursors.SizeWE;
                    }
                    else if (e.Y > con.Height - Designer.GridSize)
                    {
                        con.Cursor = Cursors.SizeNS;
                    }
                    else
                    {
                        con.Cursor = Cursors.SizeAll;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

}
